#include "Platform/OpenGL/openGLTexture2D.h"

// #define STB_IMAGE_IMPLEMENTATION
// #include <stb_image/stb_image.h>
#include "openGLTexture2D.h"

namespace CC
{

	OpenGLTexture2D::OpenGLTexture2D(uint32_t width, uint32_t height)
		: m_Width(width), m_Height(height)
	{
		CC_CORE_INFO("OpenGLTexture2D::OpenGLTexture2D\n");

        TypeName = "texture_diffuse";

		if (m_Width == 0 && m_Height == 0)
		{
			return;
		}

		m_InternalFormat = GL_RGBA8;
		m_DataFormat = GL_RGBA;

		glGenTextures(1, &m_RendererID);
		//CC_CORE_INFO("111111111OpenGLTexture2D::OpenGLTexture2D=%d\n", m_RendererID);

		glTextureStorage2D(GL_TEXTURE_2D, 1, m_InternalFormat, m_Width, m_Height);

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	}

	OpenGLTexture2D::OpenGLTexture2D(const std::string &path)
		: m_Path(path)
	{

		CC_ASSERT(0, "delete function\n");
		// int width, height, channels;
		// // stbi_set_flip_vertically_on_load(1);
		// stbi_uc *data = nullptr;
		// {
		// 	// HZ_PROFILE_SCOPE("stbi_load - OpenGLTexture2D::OpenGLTexture2D(const std::string&)");
		// 	data = stbi_load(path.c_str(), &width, &height, &channels, 0);
		// }

		// if (data)
		// {
		// 	m_IsLoaded = true;

		// 	m_Width = width;
		// 	m_Height = height;

		// 	GLenum internalFormat = GL_RGB, dataFormat = GL_RGB;
		// 	if (channels == 4)
		// 	{
		// 		internalFormat = GL_RGBA;
		// 		dataFormat = GL_RGBA;
		// 	}

		// 	m_InternalFormat = internalFormat;
		// 	m_DataFormat = dataFormat;

		// 	// glPixelStoref(GL_UNPACK_ALIGNMENT, 1);
		// 	glGenTextures(1, &m_RendererID);
		// 	glBindTexture(GL_TEXTURE_2D, m_RendererID);
		// 	CC_CORE_INFO("OpenGLTexture2D::OpenGLTexture2D=%d,path=%s\n", m_RendererID, path.c_str());

		// 	glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_Width, m_Height, 0, dataFormat, GL_UNSIGNED_BYTE, data);

		// 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		// 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		// 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		// 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

		// 	glBindTexture(GL_TEXTURE_2D, 0);
		// 	stbi_image_free(data);
		// }
	}

	OpenGLTexture2D::OpenGLTexture2D(const Font &font)
	{
        TypeName = "texture_diffuse";

		m_InternalFormat = GL_RED;
		m_DataFormat = GL_RED;

		m_Width = font.face->glyph->bitmap.width;
		m_Height = font.face->glyph->bitmap.rows;

		glPixelStoref(GL_UNPACK_ALIGNMENT, 1);
		glGenTextures(1, &m_RendererID);
		glBindTexture(GL_TEXTURE_2D, m_RendererID);
		// CC_CORE_INFO("OpenGLTexture2D::OpenGLTexture2D Font =%d\n", m_RendererID);

		glTexImage2D(GL_TEXTURE_2D, 0, m_InternalFormat, m_Width, m_Height, 0, m_DataFormat, GL_UNSIGNED_BYTE, font.face->glyph->bitmap.buffer);

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

		glBindTexture(GL_TEXTURE_2D, 0);
	}

	OpenGLTexture2D::OpenGLTexture2D(const std::string& path, unsigned char* data, int width, int height, int channels, TextureType type)
        : m_Path(path)
	{
		if (data)
		{
			m_IsLoaded = true;

            TypeName = "texture_diffuse";

			m_Width = width;
			m_Height = height;

			GLenum internalFormat = GL_RGB, dataFormat = GL_RGB;
			if (channels == 4)
			{
				internalFormat = GL_RGBA;
				dataFormat = GL_RGBA;
			}

			m_InternalFormat = internalFormat;
			m_DataFormat = dataFormat;

			// glPixelStoref(GL_UNPACK_ALIGNMENT, 1);
			glGenTextures(1, &m_RendererID);
			glBindTexture(GL_TEXTURE_2D, m_RendererID);

			glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_Width, m_Height, 0, dataFormat, GL_UNSIGNED_BYTE, data);

			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

            if (TextureType::TextureType_Repeat == type) {
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            }
            else {
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            }			

			glBindTexture(GL_TEXTURE_2D, 0);
		}
	}
	OpenGLTexture2D::~OpenGLTexture2D()
	{
		glDeleteTextures(1, &m_RendererID);
	}

	void OpenGLTexture2D::SetData(void* data, uint32_t size)
	{
		(void)data;
		(void)size;
		//uint32_t bpp = m_DataFormat == GL_RGBA ? 4 : 3;
		// HZ_CORE_ASSERT(size == m_Width * m_Height * bpp, "Data must be entire texture!");
		// glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height, m_DataFormat, GL_UNSIGNED_BYTE, data);
	}

	void OpenGLTexture2D::SetData(unsigned char* data, int width, int height, int channels, TextureType type)
	{
		//uint32_t bpp = m_DataFormat == GL_RGBA ? 4 : 3;
		// HZ_CORE_ASSERT(size == m_Width * m_Height * bpp, "Data must be entire texture!");
		// glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height, m_DataFormat, GL_UNSIGNED_BYTE, data);
		CC_ASSERT(data, "OpenGLTexture2D::SetData data is null.\n");

		m_Width = width;
		m_Height = height;

		GLenum internalFormat = GL_RGB, dataFormat = GL_RGB;
		if (channels == 4)
		{
			internalFormat = GL_RGBA;
			dataFormat = GL_RGBA;
		}

		m_InternalFormat = internalFormat;
		m_DataFormat = dataFormat;

		glBindTexture(GL_TEXTURE_2D, m_RendererID);

		glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_Width, m_Height, 0, dataFormat, GL_UNSIGNED_BYTE, data);

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		if (TextureType::TextureType_Repeat == type) {
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		}
		else {
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		}

		glBindTexture(GL_TEXTURE_2D, 0);
	}

	void OpenGLTexture2D::Bind(uint32_t slot) const
	{
		if (m_RendererID == 0)
			return;
		CC_ASSERT(m_RendererID != 0, "ASSERT: OpenGLTexture2D::Bind id=%d\n", m_RendererID);
		glActiveTexture(GL_TEXTURE0 + slot);
		glBindTexture(GL_TEXTURE_2D, m_RendererID);
		// glBindTextureUnit(slot, m_RendererID);
	}

	void CC::OpenGLTexture2D::UnBind() const
	{
		glBindTexture(GL_TEXTURE_2D, 0);
	}

	void OpenGLTexture2D::SetID(uint32_t id)
	{
		m_RendererID = id;
		//CC_CORE_INFO("111111111OpenGLTexture2D::SetID=%d\n", m_RendererID);
	}
}
